You touched on a very large topic, which can really become as complex as you allow.
Ultimately, the version control option you choose depends on what you need to achieve and how much time you need to devote to support it. These two are directly related.
The two main goals of version control are concurrent execution and tracking. Side-by-side (SxS) allows you to run multiple versions of the same DLL in one application. Without changing the build version number, this is not possible. Tracking is simply the ability to determine the exact snapshot of the code that runs on the clients machine. Both can be achieved by changing the build version, but the first can only be achieved by changing the build version.
Many will recommend that you share the version numbers in all DLL / EXEs - this is a good way to do this, since it is the most simplified approach, it also provides the least deployment flexibility.
For example, if you use some form of contract abstraction (by defining dependencies between DLLs via interfaces rather than specific types), you can split your application into several "version silos". An example of this is the client and server, where interdependence, if defined in the third assembly, your WCFs are contracted. If they are all versioned separately, you can release a new version of the server (provided that it meets the same contract) without affecting the client. And vice versa.
As you can see, you will increase the granularity of the versions as your requirements grow, but this will be eavesdropped.
The best thing you can do is exactly what you do, sit down and plan your requirements, and then outline the boundaries of the versions (which components can be separated by contracts).
It depends on the size of your testing department, but I also recommend that you take a look at the fact that the file version reflects (at least partially) the build number / date. You only increase the assembly version once for each client version, but you must have a different version of the file for each DLL collection that exits the assembly. This is because when you test and find a problem, having these unique DLL identifiers will remove any doubts as to why the DLL was created.