Reading a bit more and some help on the #ARM IRC channel later I was able to understand the exception return mechanism. Here is what I understand.
As mentioned in the CM3 TRM, the core pushes the registers r0-r3, r12 along with the status, LR and PC on to the current process stack when an exception is registered. Thus, upon exception entry the stack contains 8 words which includes the LR containing the address to return to. The hardware pop mechanism essentially reverses the same action i.e. it pops out the last 8 words during which it loads the LR into the PC to return to the interrupted function.
Thus, the context can be switched simply by moving the stack pointer to an appropriate location such that the current stack frame resembles the stack frame of a task which has just been interrupted i.e. contains the exact words in the same order.
Upon exception entry and after saving the registers on to the stack, the LR is loaded with the EXC_RETURN value. This value contains special status flags to indicate return conditions. This is also used to indicate the end of the interrupt. That is, if the ISR needs to return to a task and switch the stack pointer from the current (MSP) to the PSP it can load the LR with the appropriate EXC_VALUE (indicated in TRM) and simply do a BX LR
to switch states.