How would that work? Rust "crates" are just a compilation unit that gets linked into the resulting binary.
This is a nice exercise for compiler researchers.
I suppose it can be done on various levels, with various performance trade-offs.
By using the type system. You define your type constraints at the module interface point and when you try to link the third-party module into that interface the compiler ensures that the constraints are satisfied. Same thing the compiler is already doing in simpler cases. If you specify that a third-party library function must return an integer, the compiler will ensure that function won't unexpectedly return a string. Just like that, except the type system is expanded to enable describing more complex behaviours.
An extremely verbose effects system can resolve these dependency permissions at compile time.
However, balancing ergonomics is a the big challenge.
I personally would prefer less ergonomics for more security, but that’s likely not a broadly shared opinion.