How to split a post and intercalate elements from a loop

You can buffer the template part to use it within post content:

<?php
add_filter( 'the_content', 'add_related_each_nth_p' );

function add_related_each_nth_p( $content )
{
    if ( ! is_single() ) {
        return $content;
    }

    // the interval between added content
    $paragraph_steps = 3;

    // declare empty output
    $output="";

    // declare related posts offset
    $z = 0;

    // make the array of paragraphs
    $content = explode( '</p>', $content );

    // iterate through the content paragraphs
    for ( $i = 0; $i < count( $content ); $i++ ) {

        // concatenate paragraphs one by one
        $output .=  $content[ $i ] . '</p>';

        // check if interval is reached and if so, concatenate related
        if ( 0 == $i % $paragraph_steps ) {

            // run your query
            $related = new WP_Query( array(
                'post__in'       => $whatever,
                'posts_per_page' => '1',
                'offset'         => $z,
            ) );

            // related post offset increments by one every interval
            $z++;

            if ( $related->have_posts() ) {
                while ( $related->have_posts() ) {

                    $related->the_post();
                    // start buffering
                    ob_start();
                    get_template_part('relatedpost');
                    // concatenate related post to the output
                    $output .= ob_get_contents();
                    // Clean the output buffer
                    ob_end_clean();
                }
            }
            wp_reset_query();
        }
    }

    return $output;
}

Or you can move relatedpost template part markup to the function (see the appropriate place in the code above), for example:

<?php
if ( $related->have_posts() ) {
    while ( $related->have_posts() ) {
        $related->the_post();
        $output .= '<p>Related: ' . get_the_title() . '</p>';
    }
}

The code is not tested, though.