Dynamic WordPress rewrite rules for multiple custom post types

Jacob’s comment got me on the right track.

Here’s what worked for my issue:

add_action('init', 'cpt_rewrite');
function cpt_rewrite(){
    $args = array(
        'public'   => true,
        '_builtin' => false,
    );

    $post_types = get_post_types( $args );
    if ( $post_types ) {
        foreach ( $post_types as $post_type ) {
            add_rewrite_rule('^'.$post_type.'/([0-9]{4})/([0-9]{2})/?','index.php?post_type=".$post_type."&year=$matches[1]&monthnum=$matches[2]','top');
            add_rewrite_rule('^'.$post_type.'/([0-9]{4})/?','index.php?post_type=".$post_type."&year=$matches[1]','top'); 
        }
    }
}

I used get_post_types() to get all my registered custom post types and then loop through each of them.