If the data path uses a FIFO, as long as the pointers don’t cross the write and read paths have no asynchronous path. They're considered to be in separate clock domains. (The FIFO could even be a one- or two-level register depending on how the two sides handshake with each other.)
The managing of this pointer-cross business is dealt with by the control path, which if properly designed will ensure that the pointer-cross corner case never occurs.
An issue that comes up frequently relates to the clock ratios of read vs. write. If read clock is significantly slower, this adds turn-around latency to the write-read handshake. This comes up as the FIFO approaches full: the read pointer in the slow clock domain will take a long time to change state, delaying the FULL calculation. If the write side doesn't see this in time it can overrun the FIFO. The answer to this case is to give an earlier almost-full to the write side, so that any extra writes can still make it to the FIFO. This is called a skid buffer.
Related: what is the specific reason for using FIFO in asynchronous domain at VLSI?