you could use hook_commerce_checkout_pane_info_alter and do
unset($checkout_pane['customer_profile_shipping']);
only if all line_items contains physical products:
function mymodule_commerce_checkout_pane_info_alter(&$checkout_pane) {
global $user;
foreach ($checkout_pane as $pane_name => & $pane_data) {
if ($pane_name == 'customer_profile_shipping') {
$order = commerce_cart_order_load($user->uid);
if ($order) {
$order_wrapper = entity_metadata_wrapper('commerce_order', $order);
$lines = $order_wrapper->commerce_line_items->value();
$ask_shipping = FALSE;
foreach ($lines as $line) {
if ($line->type == 'product') {
$line_wrapper = entity_metadata_wrapper('commerce_line_item', $line);
$product = $line_wrapper->commerce_product->value();
if ($product->type == '---> you physical product type <---') {
$ask_shipping = TRUE;
}
}
}
if (!$ask_shipping) {
unset($checkout_pane['customer_profile_shipping']);
}
}
}
}
}