The front-end deals with the language itself: scanning, parsing, the parse-tree. The back end deals with the target system: object code formats, the machine code itself, … The two things don’t have all that much to do with each other, and for a portable compiler it is highly desirable to use the same front-end with multiple backends, one per target.
You can take that further, as gcc does, and have a front/backend interface that is language-independent, so you can use different language front-ends with the same backend. In the old days this was called the MxN problem: you don’t want to have to write MxN compilers where you have M languages and N target systems. The idea is to only have to write M+N compilers.
Solution to MxN Problem:
A big problem intermediate code solves is that, you don’t need a big monolithic compiler for both front-end language parsing and back-end architecture instructions. They call it MxN problem, so instead of MxN combinations of architectures and languages in a monolithic compiler – you get M+N components where M handle the language parsing etc.. while N handle the conversion from the single intermediate language/instructions to the target architecture’s instructions.