So this is a little tricky but doable. Keep in mind that I was doing this on Magento EE 1.13.
First set up a new Shopping Cart Price Rule located under
Promotions->Shopping Cart Price Rules
Next,under Rule Information->Coupon, select "No Coupon"
- Under Conditions create condition "Shipping Method is [shipping method]"
- Under Actions, set Discount Amount to 0, set Free Shipping to "For Shipment with Matching Items" and create a condition "Price in cart greater than 0.01"
Save the promotion and it should now apply to the shipping method. At first glance all the shipping methods will appear with their typical price, once the user selects the shipping method you set for the promotion, it will then be applied to the final subtotal.
However, there is a catch. If the user reenters the checkout at an earlier phase (i.e. leaves the checkout page than checks out again or selects a previous checkout step prior to the shipping methods step) once they hit the shipping methods step every shipping method will appear to be free shipping. I believe this is the problem that you are having.
So why is this happening? If you step through the code in a debugger, you will find that two things have happened. When the user goes through the Shipping Method step of the checkout process, the promotion related to the currently selected shipping method is applied. Magento stores this shipping method in the quote's address object itself, thus on the shipping methods, if the shipping method is already selected, Magento will think that free shipping applies and will apply it to every single shipping method. Selecting a different shipping method (one that the promotion does not apply to) then getting to the order subtotal page will reset the promotions resulting in the correct shipping method prices being displayed again.
How do we get around it? Although it isn't ideal, rewrite the app\design\frontend\base\default\template\checkout\onepage\shipping_method\available.phtml file in your own design folder, and add the following code to you new template file:
$this->getQuote()->getShippingAddress()->setCollectShippingRates(true);
$this->getAddress()->setShippingMethod(null);
$this->getAddress()->setFreeShipping(false);
Why do we need to do this? We are somewhat tricking Magento here. Magento will look to see if it needs to generate new shipping rates when the payment step of onepage checkout is called. If getCollectShippingRates() returns false, then it won't search for rates. For this reason, we are telling Magento, yes you need to look again. Setting shippingMethod to null will tell Magento that there isn't a shipping method selected thus not applying the promotion again. Lastly, setFreeShipping(false) will tell Magento that no promotion has been applied for free shipping yet. Basically we are resetting the shipping method selection for the quote by doing this.