Review the Pwiki, Google Analytics, or iDevAffiliate integrations as you should be building the $subscription object, followed by $plan object, then calling ->getPersonalized for the plan to get the personalized (language strings and substitutions) plan name. All 3 are utilizing such API directly inside their loadPaymentItems foreach loops.
Substitutions are not ran in most backend views, but you have not clarified what backend view this is a problem in. There also is no $product->title so I have no idea what part of your code you're referring to.