A crate cannot be stable (>=1.0.0) without all of its public dependencies being stable.
Public dependencies are crates from which types are used in the public API of the current crate.
So now I am wondering what exactly is the definition of "types are used in the public API of the current crate".
Yes, the rand crate is in your public API in both cases. Think of it like this. Let's say that your crate is using rand 0.8 and I'm also using 0.8, and I write this code:
my_function(&mut thread_rng());
That code compiles just fine.
Next, you upgrade your library from rand 0.8 to 0.9. That breaks my code! Because I have a rand 0.8 rng but I need a rand 0.9. Because you broke users by upgrading the library, it's in your public API.
Also, it can be quite hard for users to keep this sort of thing straight if they incorporate several crates that all use this trick for the same dependency. If crate_a and crate_b both re-export rand 0.8, users should maintain separate RNGs for interfacing with each crate, but there's nothing forcing them to do so.
If any cross-contamination happens, though, either crate moving to rand 0.9 will break their code.
There’s also an unstable feature to audit your code after you declare which dependencies you intend to be public; see exported-private-dependencies. It has some false positives in particular cases of (IIRC) multiple levels of re-exports, but other than that, it does give you a reasonable machine-checked definition.