Back face culling can be done in different stages. You can do it in object space, by transforming the camera position to that space. For every polygon, take the vector from one of the polgyon's vertices, and compute the dot product with the polygon's normal. The sign determines what way the polygon is facing. This approach has great performance advantages if you can precompute the normals of the model (i.e. when they are static). The only cost is the dot product.
You can also do it in camera space. The method is the same, but now the normal has to be recomputed with a cross product. If the model is static we could also transform the normal from model space to camera space, but this actually takes longer.
The last approach is in screen space. Here you just need to know whether the polygon's normal is facing to the screen or not. So only the z-component of the cross product is required. That's fast, but it requires all vertices to be transformed to screen space. In many implementations this is done anyway, to avoid complexity in the vertex pipeline and the vertex cache. I currently use this method myself, and have seen no significant performance advantage from doing culling in earlier stages.