The old DirectX SDK outlines a method for being able to do this, but it does require that you use Direct3D 9 Ex rather than just plain-old Direct 3D 9. Since 9 Ex is only available on Vista+ this may not suit your requirements.
It's covered in the section titled Feature Summary (Direct3D 9 for Windows Vista) and I'll quote it in full:
Reading Depth/Stencil Buffers
Use IDirect3DDevice9::UpdateSurface to read or write depth/stencil data from surfaces obtained from IDirect3DDevice9::CreateDepthStencilSurface or IDirect3DDevice9::GetDepthStencilSurface.
First, create a lockable, depth only or stencil only surface using IDirect3DDevice9::CreateOffscreenPlainSurface. Use one of the following formats:
- D3DFMT_D16_LOCKABLE
- D3DFMT_D32F_LOCKABLE
- D3DFMT_D32_LOCKABLE
- D3DFMT_S8_LOCKABLE
Second, transfer data between the depth/stencil buffer and the newly-created lockable depth or stencil surface. The transfer is performed using IDirect3DDevice9::UpdateSurface.
UpdateSurface will fail when both surfaces are a LOCKABLE format or both are non-lockable.
Transferring non-existent data will result in an error (for example, transferring from a non-lockable depth-only surface to a D3DFMT_S8_LOCKABLE surface).
The rest of the restrictions for IDirect3DDevice9::UpdateSurface still apply.
As @Adam suggests in his answer, you really should consider whether or not you actually need to read the depth buffer back to the CPU. That's not going to be a fast operation whichever way you do it.
I'd suggest that you give more detail about why you feel you need to do this, perhaps even making it a separate question; it may well be the case that whatever you're trying to achieve can be done without such a read-back.